from typing import Dict, List, Optional
import pandas as pd
import numpy as np
from datetime import datetime
import matplotlib.pyplot as plt
import seaborn as sns
from dataclasses import dataclass

@dataclass
class Trade:
    """交易记录"""
    timestamp: datetime
    symbol: str
    side: str
    size: float
    price: float
    pnl: float = 0.0
    stop_loss: float = 0.0
    take_profit: float = 0.0
    status: str = 'open'
    close_time: Optional[datetime] = None
    close_price: float = 0.0

class PerformanceAnalyzer:
    """性能分析器"""
    
    def __init__(self):
        """初始化性能分析器"""
        self.trades: List[Trade] = []
        self.daily_stats = pd.DataFrame()
        self.monthly_stats = pd.DataFrame()
        
    def add_trade(self, trade: Trade):
        """添加交易记录"""
        self.trades.append(trade)
        
    def update_trade(self, trade: Trade):
        """更新交易记录"""
        for i, t in enumerate(self.trades):
            if (t.timestamp == trade.timestamp and 
                t.symbol == trade.symbol and 
                t.side == trade.side):
                self.trades[i] = trade
                break
                
    def calculate_statistics(self) -> Dict:
        """计算交易统计数据"""
        if not self.trades:
            return {}
            
        # 转换为DataFrame
        trades_df = pd.DataFrame([vars(t) for t in self.trades])
        trades_df['timestamp'] = pd.to_datetime(trades_df['timestamp'])
        trades_df.set_index('timestamp', inplace=True)
        
        # 基础统计
        total_trades = len(trades_df)
        winning_trades = len(trades_df[trades_df['pnl'] > 0])
        losing_trades = len(trades_df[trades_df['pnl'] < 0])
        win_rate = winning_trades / total_trades if total_trades > 0 else 0
        
        # 收益统计
        total_pnl = trades_df['pnl'].sum()
        avg_pnl = trades_df['pnl'].mean()
        max_pnl = trades_df['pnl'].max()
        min_pnl = trades_df['pnl'].min()
        
        # 计算夏普比率
        daily_returns = trades_df['pnl'].resample('D').sum()
        sharpe_ratio = np.sqrt(252) * daily_returns.mean() / daily_returns.std() if len(daily_returns) > 0 else 0
        
        # 计算最大回撤
        cumulative_returns = (1 + daily_returns).cumprod()
        rolling_max = cumulative_returns.expanding().max()
        drawdowns = cumulative_returns / rolling_max - 1
        max_drawdown = drawdowns.min()
        
        return {
            'total_trades': total_trades,
            'winning_trades': winning_trades,
            'losing_trades': losing_trades,
            'win_rate': win_rate,
            'total_pnl': total_pnl,
            'avg_pnl': avg_pnl,
            'max_pnl': max_pnl,
            'min_pnl': min_pnl,
            'sharpe_ratio': sharpe_ratio,
            'max_drawdown': max_drawdown
        }
        
    def plot_performance(self, save_path: Optional[str] = None):
        """绘制性能分析图表"""
        if not self.trades:
            return
            
        trades_df = pd.DataFrame([vars(t) for t in self.trades])
        trades_df['timestamp'] = pd.to_datetime(trades_df['timestamp'])
        trades_df.set_index('timestamp', inplace=True)
        
        # 创建图表
        fig, axes = plt.subplots(3, 2, figsize=(15, 12))
        fig.suptitle('Trading Performance Analysis', fontsize=16)
        
        # 1. 累计收益
        daily_pnl = trades_df['pnl'].resample('D').sum()
        cumulative_pnl = daily_pnl.cumsum()
        axes[0, 0].plot(cumulative_pnl.index, cumulative_pnl.values)
        axes[0, 0].set_title('Cumulative PnL')
        axes[0, 0].set_xlabel('Date')
        axes[0, 0].set_ylabel('PnL')
        
        # 2. 每日收益分布
        sns.histplot(daily_pnl, bins=50, ax=axes[0, 1])
        axes[0, 1].set_title('Daily PnL Distribution')
        axes[0, 1].set_xlabel('PnL')
        axes[0, 1].set_ylabel('Frequency')
        
        # 3. 交易量柱状图
        monthly_trades = trades_df.resample('M').size()
        axes[1, 0].bar(monthly_trades.index.strftime('%Y-%m'), monthly_trades.values)
        axes[1, 0].set_title('Monthly Trading Volume')
        axes[1, 0].set_xlabel('Month')
        axes[1, 0].set_ylabel('Number of Trades')
        plt.setp(axes[1, 0].xaxis.get_majorticklabels(), rotation=45)
        
        # 4. 胜率饼图
        win_loss = [
            len(trades_df[trades_df['pnl'] > 0]),
            len(trades_df[trades_df['pnl'] < 0])
        ]
        axes[1, 1].pie(win_loss, labels=['Winning', 'Losing'], autopct='%1.1f%%')
        axes[1, 1].set_title('Win/Loss Ratio')
        
        # 5. 每笔交易PnL
        axes[2, 0].bar(range(len(trades_df)), trades_df['pnl'].values)
        axes[2, 0].set_title('PnL per Trade')
        axes[2, 0].set_xlabel('Trade Number')
        axes[2, 0].set_ylabel('PnL')
        
        # 6. 回撤分析
        daily_returns = trades_df['pnl'].resample('D').sum()
        cumulative_returns = (1 + daily_returns).cumprod()
        rolling_max = cumulative_returns.expanding().max()
        drawdowns = cumulative_returns / rolling_max - 1
        axes[2, 1].fill_between(drawdowns.index, drawdowns.values, 0, color='red', alpha=0.3)
        axes[2, 1].set_title('Drawdown Analysis')
        axes[2, 1].set_xlabel('Date')
        axes[2, 1].set_ylabel('Drawdown')
        
        plt.tight_layout()
        
        if save_path:
            plt.savefig(save_path)
        else:
            plt.show()
            
    def generate_report(self, save_path: Optional[str] = None) -> str:
        """生成性能报告"""
        stats = self.calculate_statistics()
        
        report = f"""
Trading Performance Report
=========================
Generated at: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}

Summary Statistics
-----------------
Total Trades: {stats['total_trades']}
Winning Trades: {stats['winning_trades']}
Losing Trades: {stats['losing_trades']}
Win Rate: {stats['win_rate']:.2%}

Profitability
------------
Total PnL: {stats['total_pnl']:.2f}
Average PnL per Trade: {stats['avg_pnl']:.2f}
Best Trade: {stats['max_pnl']:.2f}
Worst Trade: {stats['min_pnl']:.2f}

Risk Metrics
-----------
Sharpe Ratio: {stats['sharpe_ratio']:.2f}
Maximum Drawdown: {stats['max_drawdown']:.2%}
"""
        
        if save_path:
            with open(save_path, 'w') as f:
                f.write(report)
                
        return report
